﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NetfractionHub.LocalMachine.BotCommands;
using NetfractionHub.Network.Protocol;
using NetfractionHub.Network.Protocol.BASE.Factory;
using NetfractionHub.Network.Protocol.UCMD;
using NetfractionHub.Network.Protocol.UCMD.Factory;

namespace AnnouncerBot.Handlers
{
    [CommandHandler("addrelease")]
    [UserCommand("Add Release", FactoryCMD.ConextTypesEnum.FileListCommand, "HMSG {0}addrelease\\\\s%[line:Category name]\\\\s%[fileMN]\n")]
    public class AddRelease : CommandHandler
    {
        public override BotReturnStatus HandleCommandMessage(NetfractionHub.RemoteMachine.Node source, CommandMessage message)
        {
            string magnetRegexMatch = @"(?<url>(?<protocol>magnet):\?(?<params>[-A-Za-z0-9+&@#/%?=~_()|!:,.;']*[-A-Za-z0-9+&@#/%=~_()|']))";
            System.Text.RegularExpressions.Regex findUrl = new System.Text.RegularExpressions.Regex(magnetRegexMatch, System.Text.RegularExpressions.RegexOptions.IgnoreCase);

            string magnet = string.Empty;
            string catName = string.Empty;
            int catId = 0;
            int userId = 0;

            if (CheckArgumentMix(message, 2))
            {
                if (CheckArgumentMix(message, 2, 0, 0))
                {
                    if (!SetVariableToStringArgument(message, "magnet", out magnet))
                        return new BotReturnStatus(false, "No magnet link given.");

                    if (message.StringArguments.ContainsKey("categoryName"))
                    {
                        catName = message.StringArguments["categoryName"];
                        catId = GetCategoryIdFromName(catName);
                        if (catId == 0)
                            return new BotReturnStatus(false, "Cannot find category name.");
                    }
                    else if (message.StringArguments.ContainsKey("categoryId") && int.TryParse(message.StringArguments["categoryId"], out catId))
                    {
                        catName = GetCategoryNameFromId(catId);
                        if (string.IsNullOrEmpty(catName))
                            return new BotReturnStatus(false, "Cannot find category id.");
                    }
                    else
                        return new BotReturnStatus(false, "No category given.");
                }
                else if (message.UnnamedArguments.Count == 2)
                {
                    if (int.TryParse(message.UnnamedArguments[0], out catId))
                    {
                        catName = GetCategoryNameFromId(catId);
                        if (string.IsNullOrEmpty(catName))
                            return new BotReturnStatus(false, "Cannot find category id.");
                    }
                    else
                    {
                        catName = message.UnnamedArguments[0];
                        catId = GetCategoryIdFromName(catName);
                        if (catId == 0)
                            return new BotReturnStatus(false, "Cannot find category name.");
                    }
                    magnet = message.UnnamedArguments[1];
                }

                // get userId for username, or add it.
                userId = GetUserIdFromUsername(source.Identity.Nickname);
                if (userId == 0)
                {
                    userId = InsertUser(source.Identity.Nickname);
                    if (userId == 0)
                        return new BotReturnStatus(false, "Cannot find user."); // shouldn't happen?
                }

                if (string.IsNullOrWhiteSpace(magnet))
                    return new BotReturnStatus(false, "No magnet link given.");

                if (!findUrl.IsMatch(magnet))
                    return new BotReturnStatus(false, "Supplied string is not a valid magnet link.");

                Community.CsharpSqlite.SQLiteClient.SqliteCommand cmd = new Community.CsharpSqlite.SQLiteClient.SqliteCommand("INSERT INTO [Entries] ([AddedBy], [CategoryId], [Magnet]) VALUES (@addedBy, @catId, @magnet);");
                Community.CsharpSqlite.SQLiteClient.SqliteParameter addedByParam = new Community.CsharpSqlite.SQLiteClient.SqliteParameter("@addedBy", userId.ToString());
                cmd.Parameters.Add(addedByParam);
                Community.CsharpSqlite.SQLiteClient.SqliteParameter catIdParam = new Community.CsharpSqlite.SQLiteClient.SqliteParameter("@catId", catId.ToString());
                cmd.Parameters.Add(catIdParam);
                Community.CsharpSqlite.SQLiteClient.SqliteParameter magnetParam = new Community.CsharpSqlite.SQLiteClient.SqliteParameter("@magnet", magnet);
                cmd.Parameters.Add(magnetParam);

                int retVal = AnnouncerBot.DataStore.ExecuteNonQuery(cmd);
                if (retVal == 1)
                    this.ParentBot.SendBroadcastMessageFromBot(string.Format(System.Globalization.CultureInfo.InvariantCulture, "The entry {0} has been added to the Announcer database, under the category '{1}'.", magnet, catName));
            }
            else if (CheckArgumentMix(message, 1))
            {
                if (!SetVariableToStringArgument(message, "magnet", out magnet))
                {
                    if (message.UnnamedArguments.Count == 1)
                        magnet = message.UnnamedArguments[0];
                    else
                        return new BotReturnStatus(false, "Missing magnet link.");
                }

                if (!findUrl.IsMatch(magnet))
                    return new BotReturnStatus(false, "Supplied string is not a valid magnet link.");

                Community.CsharpSqlite.SQLiteClient.SqliteCommand cmd = new Community.CsharpSqlite.SQLiteClient.SqliteCommand("INSERT INTO [Entries] ([AddedBy], [Magnet]) VALUES (@addedBy, @magnet);");
                Community.CsharpSqlite.SQLiteClient.SqliteParameter addedByParam = new Community.CsharpSqlite.SQLiteClient.SqliteParameter("@addedBy", userId.ToString());
                cmd.Parameters.Add(addedByParam);
                Community.CsharpSqlite.SQLiteClient.SqliteParameter magnetParam = new Community.CsharpSqlite.SQLiteClient.SqliteParameter("@magnet", magnet);
                cmd.Parameters.Add(magnetParam);

                int retVal = AnnouncerBot.DataStore.ExecuteNonQuery(cmd);
                if (retVal == 1)
                    this.ParentBot.SendBroadcastMessageFromBot(string.Format(System.Globalization.CultureInfo.InvariantCulture, "The entry {0} has been added to the Announcer database.", magnet));
            }
            else
            {
                return false;
            }

            return true;
        }

        private int GetUserIdFromUsername(string name)
        {
            object tempVal = AnnouncerBot.DataStore.ExecuteScalar(string.Format(System.Globalization.CultureInfo.InvariantCulture, "SELECT UserId FROM Users WHERE Username='{0}'", name));
            if (tempVal != null && tempVal is Int64)
                return CastInt64ToInt((Int64)tempVal);
			else if (tempVal != null && tempVal is Int32)
				return (int)tempVal;
            else
                return 0;
        }

        private int CastInt64ToInt(Int64 num)
        {
            if (num > int.MinValue && num < int.MaxValue)
                return Convert.ToInt32(num);
            else
                return 0;
        }

        private int InsertUser(string name)
        {
            int retVal = AnnouncerBot.DataStore.ExecuteNonQuery(string.Format(System.Globalization.CultureInfo.InvariantCulture, "INSERT INTO Users (Username) VALUES ('{0}')", name));
            if (retVal == 1)
                return GetUserIdFromUsername(name);

            return 0;
        }

        private int GetCategoryIdFromName(string name)
        {
            object tempVal = AnnouncerBot.DataStore.ExecuteScalar(string.Format(System.Globalization.CultureInfo.InvariantCulture, "SELECT CategoryId FROM Categories WHERE Name='{0}'", name));
			if (tempVal != null && tempVal is Int64)
				return CastInt64ToInt((Int64)tempVal);
			else if (tempVal != null && tempVal is Int32)
				return (int)tempVal;
			else
				return 0;
        }

        private string GetCategoryNameFromId(int id)
        {
            object tempVal = AnnouncerBot.DataStore.ExecuteScalar(string.Format(System.Globalization.CultureInfo.InvariantCulture, "SELECT Name FROM Categories WHERE CategoryId='{0}'", id));
            if (tempVal != null && tempVal is string)
                return tempVal.ToString();
            else
                return string.Empty;
        }
    }
}
